﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Input;
using System.Windows.Controls.Ribbon;
using SHomeWorkshop.LunarConcept.Controls;
using System.Xml;
using SHomeWorkshop.LunarConcept.Tools;
using SHomeWorkshop.LunarConcept.ModifingManager;
using System.Windows;
using SHomeWorkshop.LunarConcept.Enums;

namespace SHomeWorkshop.LunarConcept.Commands
{
    /// <summary>
    /// 创建时间：2013年8月24日
    /// 创建者：  杨震宇
    /// 
    /// 主要用途：在当前EdirorManager中的处于MainSelected状态的PageEditor后部添加一个新的PageEditor，
    ///           并使新PageEditor成为MainSelected。
    /// </summary>
    public static class InsertPageCopyEditorCommand
    {
        #region 构造方法=====================================================================================================

        /// <summary>
        /// [静态][构造方法]
        /// 
        /// ——此方法会初始化并向WPF系统注册一个RoutedUICommand。
        /// </summary>
        static InsertPageCopyEditorCommand()//类型构造器
        {
            routedUICmd = new RoutedUICommand(
                "InsertPageCopyEditorCommand",
                "InsertPageCopyEditorCommand",
                typeof(InsertPageCopyEditorCommand),//创建RoutedUICommand对象
                null);//本程序考虑支持“命令模式”因此，这些命令完全没有必要直接支持快捷键。

            routedUICmd.InputGestures.Add(new KeyGesture(Key.P,
                ModifierKeys.Control | ModifierKeys.Alt, "Ctrl + Alt + P"));

            cmdBinding.Command = routedUICmd;
            cmdBinding.CanExecute += new CanExecuteRoutedEventHandler(cmdBinding_CanExecute);
            cmdBinding.Executed += new ExecutedRoutedEventHandler(cmdBinding_Executed);
        }

        #endregion

        #region 字段与属性===================================================================================================

        private static CommandBinding cmdBinding = new CommandBinding();
        /// <summary>
        /// 用在主窗口CommandBindings集合中的命令绑定。
        /// 
        /// 它的Command是RoutedUICommand。
        /// ——因此，RoutedUICommand是否可以运行将由CmdBinding的CanExecute事件决定。
        /// ——而且，RoutedUICommand的执行也是通过CmdBinding的Execute事件来进行的。
        /// </summary>
        public static CommandBinding CmdBinding
        {
            get { return cmdBinding; }
        }

        private static RoutedUICommand routedUICmd;
        /// <summary>
        /// [只读静态属性]表示在WPF系统中注册的一个RoutedUICommand。
        /// ——必须和CommandBinding配合才能使用。
        ///     CommandBinding要添加到主窗口的CommandBindings集合中；
        ///     RoutedUICommand则要向WPF系统注册。
        ///     
        /// ★说明：使用静态属性是因为这样在Xaml代码中比较便于绑定。
        /// </summary>
        public static RoutedUICommand RoutedUICmd
        {
            get { return routedUICmd; }
        }

        #endregion

        #region 方法=========================================================================================================

        /// <summary>
        /// 判断命令是否可以执行。
        /// ——由于可以直接调用Execute()方法，因此，即使被禁用，也不是不能执行相关功能！！！
        /// </summary>
        static void cmdBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = true;//总是可用的。
        }

        /// <summary>
        /// 命令被触发时，会调用本事件处理器方法。
        /// ——本方法实际上是调用ExeCute()这个静态方法来实现特定功能。
        /// </summary>
        static void cmdBinding_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            LunarMessage.Warning(Execute());
        }

        /// <summary>
        /// [公开静态方法]即使此命令处于禁用状态，也可以通过代码调用此方法来执行特定任务！！！
        /// 
        /// 当被绑定的命令被调用（触发）时，会引发cmdBinding_Executed事件。
        /// 在cmdBinding_Executed事件处理器方法中已添加了调用Execute()方法的代码。
        /// 
        /// ——因此，触发命令，就相当于调用此方法！！！
        /// </summary>
        public static string Execute()
        {
            if (Globals.MainWindow == null) return "　　未找到Globals.MainWindow。";

            EditorManager manager = Globals.MainWindow.EditorManager;
            if (manager == null) return "　　未找到页面管理器。";

            XmlNode pageSetNode = manager.XmlDocument.DocumentElement.SelectSingleNode(XmlTags.PageSetTag);

            if (pageSetNode == null)
            {
                pageSetNode = manager.XmlDocument.DocumentElement.
                    AppendXmlAsChild(string.Format("<{0} />", XmlTags.PageSetTag));
            }

            if (manager.Count >= 500)
            {
                MessageBoxResult r = MessageBox.Show("　　天哪！竟然超过500页！这太难想像了。真的要继续吗？",
                    Globals.AppName, MessageBoxButton.YesNo, MessageBoxImage.Warning);

                if (r != MessageBoxResult.Yes) return string.Empty;
            }

            PageEditor basePageEditor = manager.GetMainSelectedPageEditor();

            if (basePageEditor == null) basePageEditor = manager.LastPageEditor;

            if (basePageEditor == null)
            {
                //当前还没有任何页面（都被删除了）。直接添加新页面。

                XmlNode newPageNode = pageSetNode.AppendXmlAsChild(string.Format("<{0} />", XmlTags.PageTag));

                PageEditor newPageEditor = new PageEditor(manager);
                newPageEditor.XmlData = newPageNode;
                newPageEditor.NewID();

                manager.AddPageEditor(newPageEditor);

                ModifingInfo info = new ModifingInfo();

                //记录操作前被选定的所有PageEditor的ID。
                List<PageEditor> oldSelectedPageEditorList = manager.GetSelectedPageEditorsList();
                foreach (PageEditor pe in oldSelectedPageEditorList)
                {
                    info.AddPageEditorID_OldSelected(pe.Id);
                    if (pe.IsMainSelected)
                    {
                        info.OldMainSelectedPageEditorID = pe.Id;
                    }

                    if (pe.IsSelected) pe.IsSelected = false;
                }
                manager.GetSelectedWidgetStatus_Old(info);
                manager.GetSelectedWidgetStatus_New(info);

                info.NewMainSelectedPageEditorID = newPageEditor.Id;

                info.ModifingDescription = "添加新页（复制页操作未找到当前页）";

                ModifingItem<Action, ModifingInfo> mi = new ModifingItem<Action, ModifingInfo>(info);

                Action actAddPageEditor = new Action(ActionType.PageEditorAdded, newPageEditor.Id, 0, null,
                    newPageEditor.XmlData.OuterXml);
                mi.AddAction(actAddPageEditor);

                manager.RegisterModifingItem(mi);

                newPageEditor.IsMainSelected = true;

                manager.RefreshPaginations();
                return string.Empty;
            }
            else
            {
                XmlNode newPageNode = null;
                if (basePageEditor.XmlData.InsertXml(basePageEditor.XmlData.OuterXml, true))
                {
                    newPageNode = basePageEditor.XmlData.NextSibling;

                    //重建ID
                    RebuildIDsOfWidgetsInPageOrGroup(newPageNode);
                }

                if (newPageNode == null) return "　　未能顺利添加新页面节点。";

                PageEditor newPageEditor = new PageEditor(manager);
                newPageEditor.XmlData = newPageNode;
                newPageEditor.NewID();
                newPageEditor.PaperDirection = basePageEditor.PaperDirection;
                newPageEditor.PaperSize = basePageEditor.PaperSize;

                int newIndex = manager.InsertAfter(basePageEditor, newPageEditor);

                ModifingInfo info = new ModifingInfo();

                //记录操作前被选定的所有PageEditor的ID。
                List<PageEditor> oldSelectedPageEditorList = manager.GetSelectedPageEditorsList();
                foreach (PageEditor pe in oldSelectedPageEditorList)
                {
                    info.AddPageEditorID_OldSelected(pe.Id);
                    if (pe.IsMainSelected)
                    {
                        info.OldMainSelectedPageEditorID = pe.Id;
                    }

                    if (pe.IsSelected) pe.IsSelected = false;
                }
                manager.GetSelectedWidgetStatus_Old(info);
                manager.GetSelectedWidgetStatus_New(info);

                info.ModifingDescription = "复制页";

                //记录操作后被选定的（其实就是新添加的PageEditor的ID）。
                info.NewMainSelectedPageEditorID = newPageEditor.Id;
                newPageEditor.IsMainSelected = true;

                ModifingItem<Action, ModifingInfo> mi = new ModifingItem<Action, ModifingInfo>(info);

                Action actAddPageEditor = new Action(ActionType.PageEditorAdded, newPageEditor.Id, newIndex, null,
                    newPageEditor.XmlData.OuterXml);
                mi.AddAction(actAddPageEditor);

                manager.RegisterModifingItem(mi);
                manager.RefreshPaginations();
                manager.TryToDisplayPageEditor(newPageEditor, false);

                manager.MasterWindow.RefreshPageView();

                return string.Empty;
            }
        }


        // 此方法还需要换个算法：这会导致一个页面中所有部件的连接失效。
        public static void RebuildIDsOfWidgetsInPageOrGroup(XmlNode node)
        {
            if (node == null) return;
            var oldPageOrGroupID = node.GetAttributeValueText(XmlTags.IdTag);

            var newID = Guid.NewGuid().ToString();
            node.SetAttribute(XmlTags.IdTag, newID);

            var widgetSetNode = node.SelectSingleNode(XmlTags.WidgetSetTag);
            if (widgetSetNode == null) return;

            List<XmlNode> linkedLineWidgetNodesList = new List<XmlNode>();
            List<XmlNode> noLinkedLineWidgetNodesList = new List<XmlNode>();
            List<XmlNode> canbeLinkedToWidgetNodesList = new List<XmlNode>();

            #region 先分好类
            XmlNodeList list = node.ChildNodes;

            if (list != null && list.Count > 0)
            {
                foreach (XmlNode childNode in list)
                {
                    if (childNode.Name != XmlTags.WidgetTag) continue;

                    if (childNode.IsLinkLineWidgetNode())
                    {
                        linkedLineWidgetNodesList.Add(childNode);
                    }
                    else
                    {
                        var type = childNode.GetTypeAttributeValue();
                        switch (type)
                        {
                            case "BezierLine":
                            case "StraitLine":
                            case "PolyLine":
                                {
                                    noLinkedLineWidgetNodesList.Add(childNode);
                                    break;
                                }
                            default:
                                {
                                    canbeLinkedToWidgetNodesList.Add(childNode);
                                    break;
                                }
                        }
                    }
                }
            }
            #endregion

            foreach (var cNode in canbeLinkedToWidgetNodesList)
            {
                var oldWidgetId = cNode.GetIdAttributeValue();
                var newWidgetId = Guid.NewGuid().ToString();
                cNode.SetAttribute(XmlTags.IdTag, newWidgetId);

                foreach (var lNode in linkedLineWidgetNodesList)
                {
                    var attrStartMasterId = lNode.GetStartMasterIDAttributeValue();
                    var attrEndMasterId = lNode.GetEndMasterIDAttribute();

                    if (attrStartMasterId != null && attrStartMasterId.Value == oldWidgetId) attrStartMasterId.Value = newWidgetId;
                    if (attrEndMasterId != null && attrEndMasterId.Value == oldWidgetId) attrEndMasterId.Value = newWidgetId;

                    //不能放在这里，否则一条连接线的首、尾各会更新一次（因为连接到两个部件）。
                    //lNode.SetAttribute(XmlTags.IdTag, Guid.NewGuid().ToString());
                }

                if (cNode.GetTypeAttributeValue() == WidgetTypes.Group.ToString())
                {
                    RebuildIDsOfWidgetsInPageOrGroup(cNode);
                }
            }

            foreach (var lNode in linkedLineWidgetNodesList)
            {
                lNode.SetAttribute(XmlTags.IdTag, Guid.NewGuid().ToString());
            }

            foreach (var nLNode in noLinkedLineWidgetNodesList)
            {
                nLNode.SetAttribute(XmlTags.IdTag, Guid.NewGuid().ToString());
            }
        }

        #endregion
    }
}
